{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1f679dad-dc5c-4ae2-a0df-967b793c9202",
   "metadata": {},
   "source": [
    "# HW-aware Synthesis of MCX\n",
    "\n",
    "This example shows that implementation of multiple control-x (MCX) logic, using the Classiq synthesis engine, yields different circuit results for different quantum hardware.\n",
    "\n",
    "The fictitious hardware created here demonstrates how to insert your own custom-designed machine. For comparison, create two types of hardware with `cx, u` basis gates. The difference between them manifests in the connectivity map: one has linear connectivity while the other has all-to-all connectivity."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0299fa78-b416-4979-9b67-aee63e230a92",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:28:51.942647Z",
     "iopub.status.busy": "2024-05-07T13:28:51.939853Z",
     "iopub.status.idle": "2024-05-07T13:29:08.668923Z",
     "shell.execute_reply": "2024-05-07T13:29:08.668075Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/49c8fa89-91ad-4802-ae00-2fba8f3257e7?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/14a11412-f9e4-4779-ac98-339dccc1efe3?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "from classiq import (\n",
    "    CX,\n",
    "    Constraints,\n",
    "    CustomHardwareSettings,\n",
    "    H,\n",
    "    OptimizationParameter,\n",
    "    Output,\n",
    "    Preferences,\n",
    "    QArray,\n",
    "    QBit,\n",
    "    X,\n",
    "    allocate,\n",
    "    control,\n",
    "    create_model,\n",
    "    qfunc,\n",
    "    set_constraints,\n",
    "    set_preferences,\n",
    "    show,\n",
    "    synthesize,\n",
    "    write_qmod,\n",
    ")\n",
    "\n",
    "# define MCX quantum function\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def my_mcx(cntrl: QArray[QBit], target: QBit) -> None:\n",
    "    control(cntrl, lambda: X(target))\n",
    "\n",
    "\n",
    "# define the MCX parameters within the quantum 'main' function\n",
    "@qfunc\n",
    "def main(cntrl: Output[QArray[QBit]], target: Output[QBit]) -> None:\n",
    "    allocate(15, cntrl)\n",
    "    allocate(1, target)\n",
    "    my_mcx(cntrl, target)\n",
    "\n",
    "\n",
    "# build a model\n",
    "model = create_model(main)\n",
    "\n",
    "# define the hardware parameters\n",
    "max_width = 18\n",
    "\n",
    "linear_connectivity = [[qubit, qubit + 1] for qubit in range(max_width - 1)]\n",
    "\n",
    "preferences_linear = Preferences(\n",
    "    custom_hardware_settings=CustomHardwareSettings(\n",
    "        basis_gates=[\"cx\", \"u\"],\n",
    "        connectivity_map=linear_connectivity,\n",
    "    ),\n",
    "    random_seed=-1,\n",
    ")\n",
    "preferences_all_to_all = Preferences(\n",
    "    custom_hardware_settings=CustomHardwareSettings(basis_gates=[\"cx\", \"u\"]),\n",
    "    random_seed=-1,\n",
    ")\n",
    "\n",
    "# define synthesis engine constraints\n",
    "\n",
    "constraints = Constraints(optimization_parameter=\"depth\", max_width=max_width)\n",
    "\n",
    "# define models with different preferences\n",
    "model = set_constraints(model, constraints)\n",
    "\n",
    "model_linear = set_preferences(model, preferences_linear)\n",
    "model_all_to_all = set_preferences(model, preferences_all_to_all)\n",
    "\n",
    "# write models to files\n",
    "\n",
    "write_qmod(model_linear, \"hardware_aware_mcx_linear\")\n",
    "write_qmod(model_all_to_all, \"hardware_aware_mcx_all_to_all\")\n",
    "\n",
    "\n",
    "# synthesize to create quantum programs and view circuits:\n",
    "qprog_linear = synthesize(model_linear)\n",
    "show(qprog_linear)\n",
    "\n",
    "qprog_all_to_all = synthesize(model_all_to_all)\n",
    "show(qprog_all_to_all)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "638446e8-ce2d-4154-94cf-4b94d1dfe705",
   "metadata": {},
   "source": [
    "Comparison of the two circuits shows that applying MCx using different connectivity maps yields different implementation.\n",
    "\n",
    "Using \"all-to-all\" connectivity, the synthesis engine chooses as the best implementation a recourse based on \"Maslov2015\" [[1](#Maslov)] that was written on the Classiq platform. Using that, the manufactured circuit has 18 qubits; i.e., it uses two auxiliary qubits. The total depth of the circuit is 936.\n",
    "\n",
    "When using linear connectivity, the best implementation chosen by the synthesis engine is, in fact, different: an algorithm developed by Classiq, which is better suited for this map. Here, the manufactured circuit uses 17 qubits with only one auxiliary and has a depth of 1257 gates."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7012ac26-16c0-4d53-9126-7e0ab6c56f58",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "<a id='Maslov'>[1]</a>: [Maslov, D., 2016. Advantages of using relative-phase Toffoli gates with an application to multiple control Toffoli optimization. Physical Review A, 93(2), p.022311.](https://arxiv.org/pdf/1508.03273.pdf)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
